package com.coder.genreatetools;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.coder.genreatetools.model.ColumnInfo;
import com.coder.genreatetools.model.TableInfo;
import com.coder.genreatetools.service.DbMetaData;
import com.coder.genreatetools.util.Constants.DBJDBCTYPE_IBATISJDBCTYPE;
import com.coder.genreatetools.util.Constants.JAVA_TYPE;
import com.coder.genreatetools.util.Constants.JAVA_TYPE_CLASS;
import com.coder.genreatetools.util.PorcessName;

public class MysqlMetaData extends DbMetaData {

	public MysqlMetaData(Connection connection, String dbName) {
		super(connection, dbName);
	}

	/**
	 * 获得数据库中的所有表的元信息
	 * 
	 * @return
	 */
	@Override
	public List<TableInfo> getAllTableInfo() {
		ResultSet rs = null;
		List<TableInfo> tableInfoList = new ArrayList<TableInfo>();
		try {
			DatabaseMetaData dbmd = connection.getMetaData();
			rs = dbmd.getTables(dbName, null, null, new String[] { "TABLE" });
			while (rs.next()) {
				TableInfo tableInfo = new TableInfo();
				tableInfo.setTableName(rs.getString("TABLE_NAME"));
				tableInfo.setTableRemark(rs.getString("REMARKS"));
				tableInfo.setTableRemark(getTableComment(rs.getString("TABLE_NAME"), dbName));
				String className = PorcessName.getJavaClassName(tableInfo.getTableName()); // 获取java类的名称
				tableInfo.setTableClassName(className);
				tableInfo.setObjectBeanName(className.replaceFirst(className.substring(0, 1), className.substring(0, 1)	.toLowerCase())); // 设置对象名称
				tableInfo.setTablePk(getPrimaryKey(tableInfo.getTableName()));
				List<ColumnInfo> columnInfos = getColumnInfo(tableInfo);
				tableInfo.setTableColumns(columnInfos);
				tableInfo.setClassImports(getClassImports(columnInfos));
				tableInfoList.add(tableInfo);
			}
		    } catch (Exception e) {
			e.printStackTrace();
		    } finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		return tableInfoList;
	}

	/**
	 * 获取表的注释
	 * 
	 * @param tableName
	 * @param schema
	 * @return
	 */
	private String getTableComment(String tableName, String schema) {
		ResultSet rs = null;
		String tableComment = "";
		try {
			PreparedStatement pstm = connection
					.prepareStatement("SELECT t.table_comment FROM information_schema.tables t WHERE t.table_schema =? AND t.table_name=?");
			pstm.setString(1, schema);
			pstm.setString(2, tableName);
			rs = pstm.executeQuery();
			if (rs.next()) {
				tableComment = rs.getString("table_comment");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null)
					rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return tableComment;
	}

	/**
	 * 取得部分表的元数据信息
	 * 
	 * @param tableNameList
	 * @return
	 */
	@Override
	public List<TableInfo> getTableInfo(List<String> tableNameList) {
		return null;
	}

	/**
	 * 根据表名，获得表中列的元数据信息
	 * 
	 * @param tableInfo
	 * @return
	 */
	@Override
	public List<ColumnInfo> getColumnInfo(TableInfo tableInfo) {
		List<ColumnInfo> columnInfoList = new ArrayList<ColumnInfo>();
		ResultSet rs = null;
		ResultSet tableRs = null;
		int index = 1;

		try {
			DatabaseMetaData dbmd = connection.getMetaData();
			PreparedStatement pst = connection
					.prepareStatement("select * from "
							+ tableInfo.getTableName() + " where 1=2");
			tableRs = pst.executeQuery();
			rs = dbmd.getColumns(dbName, null, tableInfo.getTableName(), null);
			ResultSetMetaData meta = tableRs.getMetaData();
			
			boolean isNullable = true;
			while (rs.next()) {
				isNullable = (meta.isNullable(index) == ResultSetMetaData.columnNullable);
				
				ColumnInfo columnInfo = new ColumnInfo();
				columnInfo.setJdbcName(rs.getString("COLUMN_NAME"));
				columnInfo.setJdbcType(meta.getColumnTypeName(index));
				columnInfo.setJavaName(PorcessName.replaceUnderlineAndfirstToUpper(columnInfo.getJdbcName()));
				columnInfo.setJavaType(PorcessName.getJavaTypeForMySql(meta.getColumnTypeName(index), isNullable)); //设置jdbctype
				columnInfo.setRemark(rs.getString("REMARKS"));
				columnInfo.setIbatisJdbcType(DBJDBCTYPE_IBATISJDBCTYPE.MYSQL_JDBC_TYPE_MAP.get(meta.getColumnTypeName(index)));
				columnInfo.setJdbcNullable(isNullable);
				columnInfo.setJdbcScale(meta.getScale(index));
				columnInfo.setJdbcPrecision(meta.getPrecision(index));
				columnInfo.setDefaultValue(rs.getString("COLUMN_DEF"));
				if (pkName.equals(columnInfo.getJdbcName())) {
					columnInfo.setJdbcIsKey(true);
					tableInfo.setTablePkInfo(columnInfo);
				} else {
					columnInfo.setJdbcIsKey(false);
				}
				columnInfoList.add(columnInfo);
				index++;
			}

		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		return columnInfoList;
	}

	/**
	 * 根据表名得到表的主键元数据信息
	 * 
	 * @param tableName
	 * @return
	 */
	String pkName = "";

	@Override
	public String getPrimaryKey(String tableName) {
		ResultSet rs = null;

		try {
			DatabaseMetaData dbmd = connection.getMetaData();
			rs = dbmd.getPrimaryKeys(dbName, null, tableName);
			if (rs.next()) {
				pkName = rs.getString("COLUMN_NAME");
			} else {
				pkName = "没有主键";
				throw new RuntimeException("表" + tableName + "没有主键");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		return pkName;
	}

	/**
	 * 获取类的引用
	 * 
	 * @param columnInfos
	 * @return
	 */
	private List<String> getClassImports(List<ColumnInfo> columnInfos) {
		ArrayList<String> classImports = new ArrayList<String>();

		String javaType = "";
		for (ColumnInfo columnInfo : columnInfos) {
			javaType = columnInfo.getJavaType();
			// javaType是Date类型，并且classImports中不存在Date对应的类引用，则保存Date对应的类引用
			if (JAVA_TYPE.DATE.equals(javaType)
					&& !classImports.contains(JAVA_TYPE_CLASS.DATE)) {
				classImports.add(JAVA_TYPE_CLASS.DATE);
			}
		}

		return classImports;
	}

}
